#pragma once

/** \file    xtd/guard.h
  * \brief   Provided guarded_run(...) template function executes any object and catches all exceptons.
  * \date    2002 - 2004
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/include/xtd/guard.h,v 1.2 2004/06/05 14:16:27 cscom1r4 Exp $
  */

#include <iostream>
#include <exception>

namespace xtd {

inline void cerr_handler(const char* what)
{
	std::cerr << what << std::endl;
}

/// safely executes a function,
/// if the execution was interrupted by an exception, it returns result constructed by default ctor
template <typename F>
typename F::result_type guarded_run(F const & f, void (*handler)(const char*) = cerr_handler)
{
	try {
		return f();
	}
	catch (std::exception &e) {
		handler(e.what());
		return typename F::result_type();
	}
	catch (...) {
		handler("Critical error occurred!");
		return typename F::result_type();
	}
}

template <typename R>
struct binded_noarg_function
{
public:
	typedef R result_type;
public:
	R (*func)();
public:
	binded_noarg_function(R (*f)()) : func(f) { }
	R operator () () const { return func(); }
};

// overloaded for no argument functions run convinience
template <typename R>
inline R guarded_run(R (*f)(), void (*handler)(const char*) = cerr_handler)
{
	return guarded_run(binded_noarg_function<R>(f), handler);
}

template <typename R, typename A>
struct binded_unary_function
{
public:
	typedef R result_type;
public:
	R (*func)(A);
	A arg;
public:
	binded_unary_function(R (*f)(A), A a) : func(f), arg(a) { }
	R operator () () const { return func(arg); }
};

// overloaded for unary functions run convinience
template <typename R, typename A>
inline R guarded_run(R (*f)(A), A a, void (*handler)(const char*) = cerr_handler)
{
	return guarded_run(binded_unary_function<R,A>(f,a), handler);
}

template <typename R, typename A1, typename A2>
struct binded_binary_function
{
public:
	typedef R result_type;
public:
	R (*func)(A1, A2);
	A1 arg1;
	A2 arg2;
public:
	binded_binary_function(R (*f)(A1, A2), A1 a1, A2 a2) : func(f), arg1(a1), arg2(a2) { }
	R operator () () const { return func(arg1, arg2); }
};

// overloaded for binary functions run convinience
template <typename R, typename A1, typename A2>
inline R guarded_run(R (*f)(A1, A2), A1 a1, A2 a2, void (*handler)(const char*) = cerr_handler)
{
	return guarded_run(binded_binary_function<R,A1,A2>(f,a1,a2), handler);
}

} //namespace xtd
